#include "sys/Memory.h"
#include "NOW.h"
#include "sys/IO.h"
#include "sys/TLB.h"
static void Log(const char *format, ...){
    va_list args;
    va_start(args, format);          // 初始化va_list
    vfprintf(stdout,format, args);  // 将参数传递给vfprintf
    va_end(args);   
}
//设计磁盘调度，暂时省略
int write_back_frame(int ppn,int T){
    Log("[%d] Prepare for writing frame %d back to Disk block %d.\n", T, ppn,frame_table[ppn].blk);
    T+=100;
    Log("[%d] Finish writing frame %d back.\n", T, ppn);
}
int Mmap(int pid,int T){
    Process *proc = &jobs[pid];
    //这里我认为只修改进程内存相关的内容，剩余的交给进程
    proc->page_fault_cnt = 0;
    proc->page_find_cnt = 0;
    //对于fork的进程在一开始也一视同仁allocate_frame()，但写后复制的frame，也只能存放在一开始分配好的区域内。
    proc->allocated_frames = allocate_frames(pid,T);
    //Copy-on-write 页表独立，但指向相同的frame
    proc->PTB = init_pageTable();
    if (!proc->PTB) {
        Log("[%d] Failed to allocate page table for PID %d\n", T, pid);
        return 0;
    }
    if (proc->pa_id!=-1){//存在父进程，Fork来的
        Process *parent = &jobs[proc->pa_id];
        proc->sp = parent->sp;
        proc->hp = parent->hp;
        //Copy page_table
        PageTableEntry *pe=proc->PTB->e;
        for (int i=0;i<VIR_PAGE_NUM;++i){
            get_latest_PTE(proc->pa_id,i,&pe[i],T);//考虑WB，父页表某些项最新状态在TLB中
            if (pe[i].v){
               //修改指向frame的ref;
                unsigned ppn = pe[i].PPN;
                ++frame_table[ppn].ref;
                frame_table[ppn].refSrc = new_frame_refSrc(pid,i,frame_table[ppn].refSrc);
            }
        }

        Log("[%d] Process %d created via fork. Inherited parent PID %d's page table.\n", T, pid, proc->pa_id);
    }else{//独立进程，载入内存
        proc->sp = SP_INIT;
        proc->hp = HP_INIT;
        
        Log("[%d] Process %d loaded with empty page table.\n", T, pid);
    }
    return 1;
}
int Munmap(int pid, int T) {
    Process *proc = &jobs[pid];
    if (proc->id==-1 || !proc->PTB){
        Log("[%d] Error: Trying to unmap a unmapped process %d!\n",T,pid);
        return 0;
    }
    PageTableEntry pe;
    //释放页表分配的内存
    for (unsigned vpn = 0; vpn < VIR_PAGE_NUM; ++vpn) {
        //确保该程序和相应页表存在
        get_latest_PTE(pid,vpn,&pe,T);
        if (pe.v){
            unsigned ppn = pe.PPN;
            //考虑dirtybit， write_back
            if (pe.d){
                write_back_frame(ppn,T);
            }
            
            if (--frame_table[ppn].ref == 0){
                release_frame(ppn,T);
                //这里没必要在TLB去掉所有ppn的项，因为既然清掉frame，就说明只有一页表项指向它，可以用delE快速删除
            }
            TLB_delE(pid,vpn,T);
        }
    }
    //释放页表本身占据的内核内存
    destroy_pageTable(proc->PTB);
    proc->PTB = (void *)0;

    Log("[%d] Process %d unmapped and resources released.\n", T, pid);
    return 1;
}